package com.example.spring.statmachine.example.services.impl;

import cn.hutool.core.util.StrUtil;
import com.example.spring.statmachine.example.bo.ExtendedVariablesBO;
import com.example.spring.statmachine.example.constans.CommonConstants;
import com.example.spring.statmachine.example.domain.TbOrder;
import com.example.spring.statmachine.example.enums.OrderStatusChangeEventEnum;
import com.example.spring.statmachine.example.enums.OrderStatusEnum;
import com.example.spring.statmachine.example.mapper.OrderMapper;
import com.example.spring.statmachine.example.services.OrderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.ObjectStateMachine;
import org.springframework.statemachine.persist.StateMachinePersister;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;

/**
 * @author zhangwenxue
 */
@Service
public class OrderServiceImpl  implements OrderService {

    public static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);

    @Resource
    private ObjectStateMachine<OrderStatusEnum, OrderStatusChangeEventEnum> orderStateMachine;
    @Resource
    private StateMachinePersister<OrderStatusEnum, OrderStatusChangeEventEnum, String> stateMachineMemPersister;
    @Resource
    private OrderMapper orderMapper;

    @Override
    public TbOrder getById(Long id) {
        return orderMapper.selectById(id);
    }

    @Override
    public void create(TbOrder order) {
        order.setStatus(OrderStatusEnum.WAIT_PAYMENT.getKey());
        order.setUpdateTime(new Date());
        order.setCreateTime(new Date());
        orderMapper.insertSelective(order);
    }

    @Override
    public void pay(Long id) {
        TbOrder tbOrder = orderMapper.selectById(id);
        logger.info("线程名称：{},尝试支付，订单号：{}" ,Thread.currentThread().getName() , id);
        ExtendedVariablesBO extendedVariablesBO = this.sendEvent(OrderStatusChangeEventEnum.PAYED, tbOrder, CommonConstants.PAY_TRANSITION);
        if (!extendedVariablesBO.getState()) {
            String errorMsg = StrUtil.isBlank( extendedVariablesBO.getErrorMsg())?"":extendedVariablesBO.getErrorMsg();
            logger.error("线程名称：{},支付失败, 状态异常，订单信息：{}", Thread.currentThread().getName(), tbOrder);
            throw new RuntimeException("支付失败, 订单状态异常:"+errorMsg);
        }
    }


    @Override
    public void deliver(Long id) {
        TbOrder tbOrder = orderMapper.selectById(id);
        logger.info("线程名称：{},尝试发货，订单号：{}" ,Thread.currentThread().getName() , id);
        ExtendedVariablesBO extendedVariablesBO = this.sendEvent(OrderStatusChangeEventEnum.PAYED, tbOrder, CommonConstants.DELIVER_TRANSITION);
        if (!extendedVariablesBO.getState()) {
            String errorMsg = StrUtil.isBlank( extendedVariablesBO.getErrorMsg())?"":extendedVariablesBO.getErrorMsg();
            logger.error("线程名称：{},发货失败, 状态异常，订单信息：{}", Thread.currentThread().getName(), tbOrder);
            throw new RuntimeException("发货失败, 订单状态异常:"+errorMsg);
        }
    }

    @Override
    public void receive(Long id) {
        TbOrder tbOrder = orderMapper.selectById(id);
        ExtendedVariablesBO extendedVariablesBO = this.sendEvent(OrderStatusChangeEventEnum.PAYED, tbOrder, CommonConstants.RECEIVE_TRANSITION);
        logger.info("线程名称：{},尝试收货，订单号：{}" ,Thread.currentThread().getName() , id);
        if (!extendedVariablesBO.getState()) {
            String errorMsg = StrUtil.isBlank( extendedVariablesBO.getErrorMsg())?"":extendedVariablesBO.getErrorMsg();
            logger.error("线程名称：{},收货失败, 状态异常，订单信息：{}", Thread.currentThread().getName(), tbOrder);
            throw new RuntimeException("收货失败, 订单状态异常:"+errorMsg);
        }
    }

    /**
     * 发送订单状态转换事件
     * synchronized修饰保证这个方法是线程安全的
     * @param changeEvent changeEvent
     * @param order order
     * @return boolean
     */
    private synchronized  ExtendedVariablesBO sendEvent(OrderStatusChangeEventEnum changeEvent, TbOrder order,String key) {
        ExtendedVariablesBO extendedVariablesBO = new ExtendedVariablesBO();
        extendedVariablesBO.setState(Boolean.FALSE);
        try {
            //启动状态机
            orderStateMachine.start();
            //尝试恢复状态机状态
            stateMachineMemPersister.restore(orderStateMachine, String.valueOf(order.getId()));
            Message<OrderStatusChangeEventEnum> message = MessageBuilder.withPayload(changeEvent).setHeader("order", order).build();
            boolean result = orderStateMachine.sendEvent(message);
            if (!result){
                return extendedVariablesBO;
            }
            //获取到监听的结果信息
             extendedVariablesBO = (ExtendedVariablesBO) orderStateMachine.getExtendedState().getVariables().get(key + order.getId());
            // 如果事务执行成功，则持久化状态机
            if(extendedVariablesBO.getState()){
                //持久化状态机状态
                stateMachineMemPersister.persist(orderStateMachine, String.valueOf(order.getId()));
            }else {
                //订单执行业务异常
                logger.error("sendEvent#failed：{}",extendedVariablesBO.getErrorMsg());
                return extendedVariablesBO;
            }
        }catch (Exception e){
            logger.error("订单操作失败:{}",e.getMessage(), e);
            extendedVariablesBO.setErrorMsg(e.getMessage());
        }finally {
            orderStateMachine.stop();
        }
        return extendedVariablesBO ;
    }

}
